package top.tangyh.lamp.care.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.tangyh.basic.context.ContextUtil;
import top.tangyh.basic.exception.BizException;
import top.tangyh.lamp.base.service.system.BaseRoleService;
import top.tangyh.lamp.care.common.ObsvCfgIndexDto;
import top.tangyh.lamp.care.entity.BDevBind;
import top.tangyh.lamp.care.entity.BObsvCfg;
import top.tangyh.lamp.care.mapper.BDevBindMapper;
import top.tangyh.lamp.care.mapper.BObsvCfgMapper;
import top.tangyh.lamp.care.mapper.BObsvRecordMapper;
import top.tangyh.lamp.care.service.BObsvCfgService;
import top.tangyh.lamp.care.service.BObsvPtCfgService;
import top.tangyh.lamp.care.service.BObsvRecordService;
import top.tangyh.basic.base.service.impl.SuperServiceImpl;
import top.tangyh.lamp.care.manager.BObsvRecordManager;
import top.tangyh.lamp.care.entity.BObsvRecord;
import top.tangyh.lamp.care.service.BWorkPlanService;
import top.tangyh.lamp.care.vo.query.*;
import top.tangyh.lamp.care.vo.result.*;
import top.tangyh.lamp.care.vo.save.BObsvRecordSaveVO;
import top.tangyh.lamp.care.vo.update.BObsvRecordUpdateVO;
import top.tangyh.lamp.common.constant.CommonConstant;
import top.tangyh.lamp.common.constant.ObsvConstant;
import top.tangyh.lamp.common.utils.ConvertUtil;
import top.tangyh.lamp.common.utils.PDateUtils;
import top.tangyh.lamp.common.utils.YDateUtils;
import top.tangyh.lamp.oauth.biz.OauthUserBiz;
import top.tangyh.lamp.oauth.vo.result.DefUserInfoResultVO;

import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 业务实现类
 * 观察项记录表
 * </p>
 *
 * @author zqb
 * @date 2024-07-24 15:47:49
 * @create [2024-07-24 15:47:49] [zqb] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class BObsvRecordServiceImpl extends SuperServiceImpl<BObsvRecordManager, Long, BObsvRecord> implements BObsvRecordService {


    private final BObsvRecordMapper bObsvRecordMapper;

    private final BObsvPtCfgService bObsvPtCfgService;

    private final BWorkPlanService bWorkPlanService;

    private final BaseRoleService baseRoleService;

    private final BDevBindMapper bDevBindMapper;

    private final BObsvCfgService bObsvCfgService;


    private final OauthUserBiz oauthUserBiz;


    String MODEL_NAME_TIME_AXIOS = "hlcz";


    @Override
    public List<BObsvRecord> getTemperatureTOfBreathingListData(String hospitalNumber, String startTime, String endTime) {
        return bObsvRecordMapper.getTemperatureTOfBreathingListData(hospitalNumber, startTime, endTime);
    }

    @Override
    public List<BObsvRecord> getBloodPressureListData(String hospitalNumber, String startTime, String endTime) {
        return bObsvRecordMapper.getBloodPressureListData(hospitalNumber, startTime, endTime);
    }

    @Override
    public Map<String, List<BObsvRecord>> getDevTwdObsvRecord(String patientIdent, String hospitalNumber, Date startTime, Date endTime) {
//        return null;

        //还没对接 呼吸机设备 先 造测试数据
        List<BObsvRecord> records = createTestData();

        // 过滤数据
        List<BObsvRecord> filteredRecords = records.stream()
                .filter(record -> record.getPatientIdent().equals(patientIdent))
                .filter(record -> record.getHospitalNumber().equals(hospitalNumber))
//                .filter(record -> {
//                    Date recTime = new Date(record.getRecTime());
//                    return recTime.after(startTime) && recTime.before(endTime);
//                })
                .collect(Collectors.toList());
// 按照 obsvCode 进行分组
        Map<String, List<BObsvRecord>> groupedRecords = filteredRecords.stream()
                .collect(Collectors.groupingBy(BObsvRecord::getObsvCode));
        // 按照时间段进行分组（模拟的时间段分组，这里按小时分组）
//        Map<String, List<BObsvRecord>> groupedRecords = filteredRecords.stream()
//                .collect(Collectors.groupingBy(record -> {
//                    Date recTime = new Date(record.getRecTime());
//                    Calendar calendar = Calendar.getInstance();
//                    calendar.setTime(recTime);
//                    int hour = calendar.get(Calendar.HOUR_OF_DAY);
//                    return hour < 12 ? "上午" : "下午";
//                }));

        return groupedRecords;
    }


    /**
     * 创建测试数据
     */
    public static List<BObsvRecord> createTestData() {
        List<BObsvRecord> records = new ArrayList<>();

        // 创建 10 条测试数据
        for (int i = 0; i < 10; i++) {
            BObsvRecord record = BObsvRecord.builder()
                    .patientIdent("14024049")
                    .hospitalNumber("00369591")
                    .obsvCode("pe")
                    .propValue(String.valueOf(90 + i))  // 模拟生命体征值
                    .recTime(System.currentTimeMillis() - i * 1000 * 60 * 60)  // 模拟时间，每条记录相隔一小时
                    .isRange(1)
                    .isDeleted(0)
                    .isVisible(1)
                    .diffDay("2024-05-01")
                    .build();
            BObsvRecord record2 = BObsvRecord.builder()
                    .patientIdent("14024049")
                    .hospitalNumber("00369591")
                    .obsvCode("resp")
                    .propValue(String.valueOf(90 + i))  // 模拟生命体征值
                    .recTime(System.currentTimeMillis() - i * 1000 * 60 * 60)  // 模拟时间，每条记录相隔一小时
                    .isRange(1)
                    .isDeleted(0)
                    .isVisible(1)
                    .diffDay("2024-05-01")
                    .build();
            BObsvRecord record3 = BObsvRecord.builder()
                    .patientIdent("14024049")
                    .hospitalNumber("00369591")
                    .obsvCode("xy")
                    .propValue(String.valueOf(90 + i))  // 模拟生命体征值
                    .recTime(System.currentTimeMillis() - i * 1000 * 60 * 60)  // 模拟时间，每条记录相隔一小时
                    .isRange(1)
                    .isDeleted(0)
                    .isVisible(1)
                    .diffDay("2024-05-01")
                    .build();
            records.add(record);
            records.add(record2);
            records.add(record3);
        }

        return records;
    }


    @Override
    public List<BObsvRecord> getTemperaListData(String hospitalNumber, Long startTime, Long endTime) {
        return bObsvRecordMapper.getTemperaListData(hospitalNumber, startTime, endTime);
    }

    @Override
    public List<BObsvRecord> getShitListData(String hospitalNumber, String startTime, String endTime) {

        return bObsvRecordMapper.getShitListData(hospitalNumber, startTime, endTime);
    }

    @Override
    public boolean hasAllVal(ObsvRecordQueryParam param) {

        //获得最终可用配置项目集合
        Set<String> validObsvCodeSet = bObsvPtCfgService.getObsvCodeSetFinalOfLeaf(new ObsvPtCfgForRdParam(param.getPatientIdent()));

        List<Long> roIds = baseRoleService.findRoleIdByEmployeeId(ContextUtil.getEmployeeId());
        Long roleId = null;
        //这里这样处理的前提是 每个用户只能有一个角色，为了这个逻辑后台管理必须限制 一个用户只能绑定一个角色
        if (roIds.size() > 0) {
            roleId = roIds.get(0);
        }

        //时间轴
        Set<Long> timeBaseAxios = null;
        if (param.getStartTime() != null || param.getEndTime() != null) {
            timeBaseAxios = bWorkPlanService.getTimePoitSet(MODEL_NAME_TIME_AXIOS, roleId, param.getStartTime(), param.getEndTime()
            );
        } else if (param.getShiftTime() != null && param.getShiftCode() != null) {
            timeBaseAxios = bWorkPlanService.getTimePoitSetByShift(MODEL_NAME_TIME_AXIOS, param.getHospitalNumber(), roleId, param.getShiftTime(), Convert.toLong(param.getShiftCode()));
        }
        if (timeBaseAxios.size() <= 1) {
            return true;
        }
        List<Long> timeBaseAxiosList = timeBaseAxios.stream().sorted().collect(Collectors.toList());
        //删除最后个时间坐标（因为这个坐标是截止时间点不需要填值）
        timeBaseAxiosList.remove(timeBaseAxiosList.size() - 1);

        //获取记录中的 有值的坐标（观察项:时间）
        LambdaQueryWrapper<BObsvRecord> queryWrapper = getQueryWrapper(param);
        queryWrapper.ne(BObsvRecord::getPropValue, "");
        queryWrapper.isNotNull(BObsvRecord::getPropValue);
        List<BObsvRecord> list = bObsvRecordMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(list)) {
            return false;
        }
        Set<String> rdKeySet = new LinkedHashSet<>();
        for (BObsvRecord o : list) {
            String obsvCode = o.getObsvCode();
            String value = o.getPropValue();
            Long time = o.getRecTime();
            if (StrUtil.isNotBlank(value) && StrUtil.isNotBlank(obsvCode) && time != null) {
                //缓存坐标
                rdKeySet.add(contactByCodeAndTime(obsvCode, time));
            }
        }

        //遍历坐标构成的二维矩阵，检查是否有值
        for (String code : validObsvCodeSet) {
            for (Long time : timeBaseAxiosList) {
                //如果没有缓存的有记录的坐标，则表示该坐标下没有值，
                if (!rdKeySet.contains(contactByCodeAndTime(code, time))) {
                    return false;
                }
            }
        }

        return true;
    }

    public String contactByCodeAndTime(String code, Long time) {
        return code + ":" + Convert.toStr(time);
    }


    private LambdaQueryWrapper<BObsvRecord> getQueryWrapper(ObsvRecordQueryParam param) {
        LambdaQueryWrapper<BObsvRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BObsvRecord::getIsDeleted, CommonConstant.NO_NUMBER);
        queryWrapper.eq(param.getId() != null, BObsvRecord::getId, param.getId());
        queryWrapper.eq(StrUtil.isNotBlank(param.getPatientIdent()), BObsvRecord::getPatientIdent, param.getPatientIdent());
        if (param.getStartTime() != null || param.getEndTime() != null) {
            queryWrapper.ge(param.getStartTime() != null, BObsvRecord::getRecTime, param.getStartTime());
            queryWrapper.le(param.getEndTime() != null, BObsvRecord::getRecTime, param.getEndTime());
        } else if (param.getShiftTime() != null && param.getShiftCode() != null) {
            WorkPlanDetailOutVO wsorkPlanDetailOutVO = getShiftTimeSlot(param.getShiftTime(), param.getShiftCode());
            if (wsorkPlanDetailOutVO == null) {
                throw new BizException("班次定义为空");
            }

            queryWrapper.ge(wsorkPlanDetailOutVO.getStartTime() != null, BObsvRecord::getRecTime, wsorkPlanDetailOutVO.getStartTime());
            queryWrapper.le(wsorkPlanDetailOutVO.getEndTime() != null, BObsvRecord::getRecTime, wsorkPlanDetailOutVO.getEndTime());
        }
        return queryWrapper;
    }

    /**
     * 呼吸机使用天数
     */
    @Override
    public Integer getUeDaysWithBreathe(String patientIdent, Long changeShiftTime) {
        Integer rst = -1;
        if (StrUtil.isBlank(patientIdent)) {
            log.warn("病人识别号为空");
            return rst;
        }
        if (changeShiftTime == null) {
            log.warn("交班日期不能为空");
            return rst;
        }

        BDevBind yxDevBindPO = bDevBindMapper.getOneDevBindByPidAndDevType(patientIdent, ObsvConstant.DEV_BIND_BREATHE);

        if (yxDevBindPO == null || yxDevBindPO.getBindTime() == null) {
            log.warn("该病人没有绑定信息,或绑定时间不存在(" + patientIdent + ")");
            return rst;
        }

        Long bindTime = yxDevBindPO.getBindTime();

        bindTime = (DateUtil.beginOfDay(new Date(bindTime))).getTime();
        changeShiftTime = (DateUtil.endOfDay(new Date(changeShiftTime))).getTime();

        Set<String> typeFilte = Stream.of(ObsvConstant.OBSV_TYPE_BREATHE).collect(Collectors.toSet());
        Map<String, Set<String>> cfgMap = bObsvPtCfgService.getObsvCodeSetFinalOfLeafByType(new ObsvPtCfgForRdParam(patientIdent), typeFilte);
        if (CollectionUtil.isEmpty(cfgMap)) {
            log.warn("没有获取到病人的呼吸的观察项配置（{})", patientIdent);
            return rst;
        }
        List<String> cfgList = cfgMap.values().stream().findFirst().get().stream().collect(Collectors.toList());

        rst = bObsvRecordMapper.getUseDays(patientIdent, bindTime, changeShiftTime, cfgList, null);
        return rst;
    }

    @Override
    public WorkPlanDetailOutVO getShiftTimeSlot(Long currTime, Long shiftId) {
        List<Long> roIds = baseRoleService.findRoleIdByEmployeeId(ContextUtil.getEmployeeId());
        Long roleId = null;
        //这里这样处理的前提是 每个用户只能有一个角色，为了这个逻辑后台管理必须限制 一个用户只能绑定一个角色
        if (roIds.size() > 0) {
            roleId = roIds.get(0);
        }

        WorkPlanDetailQueryVO queryInVO = new WorkPlanDetailQueryVO();
        queryInVO.setModuleId(MODEL_NAME_TIME_AXIOS);
        queryInVO.setCurrentDate(DateUtil.beginOfDay(new Date(currTime)).getTime());
        queryInVO.setRoleId(roleId);
        queryInVO.setWorkId(shiftId);
        List<WorkPlanDetailOutVO> list = bWorkPlanService.selectDetailListByQuery(queryInVO);
        return list.get(0);
    }

    @Override
    public List<BObsvRecordResultVO> queryOld(ObsvRecordQueryParam param) {
        LambdaQueryWrapper<BObsvRecord> queryWrapper = getQueryWrapper(param);
        List<BObsvRecord> list = bObsvRecordMapper.selectList(queryWrapper);
        List<BObsvRecordResultVO> rst = new ArrayList<>();
        if (list.isEmpty()) {
            return rst;
        }

        //---------------数据处理
        ObsvCfgIndexDto cfgIndex = getProp2Cfg();//获得生命特征参数的配置索引。

        Map<String, BObsvRecord> rdCach = new LinkedHashMap<>();//记录缓存，key:参数名+记录时间
        Map<String, BObsvRecordResultVO> stuctCach = new LinkedHashMap<>();//结构体记录缓存，key:参数名+记录时间

        for (BObsvRecord rdSrc : list) {
            String propCode = rdSrc.getObsvCode();
            String recTime = Convert.toStr(rdSrc.getRecTime());
            String cacheKey = propCode + ":" + recTime;
            rdCach.put(cacheKey, rdSrc);
        }


        for (BObsvRecord rdSrc : list) {
            String propCode = rdSrc.getObsvCode();
            String recTime = Convert.toStr(rdSrc.getRecTime());
            String cacheKey = propCode + ":" + recTime;
            rdCach.put(cacheKey, rdSrc);
            ObsvCfgDto cfg = cfgIndex.getPropIndex().get(propCode);

            BObsvRecordResultVO rstItem = BeanUtil.copyProperties(rdSrc, BObsvRecordResultVO.class);
            if (cfg != null) {
                rstItem.setObsvName(cfg.getObsvName());
                rstItem.setDataType(cfg.getDataType());
                rstItem.setObsvType(cfg.getObsvType());
            }

            if (cfg != null && Convert.toInt(cfg.getIsVisible()) == ObsvConstant.YES_NUMBER) {
                rst.add(rstItem);
            }

            Set<String> cfgStructSet = cfgIndex.getStructIndex().get(propCode);
            if (CollectionUtil.isNotEmpty(cfgStructSet)) {//结构体处理
                for (String prodCodeStruct : cfgStructSet) {
                    BObsvRecordResultVO structRd = stuctCach.get(prodCodeStruct + ":" + recTime);
                    if (structRd == null) {
                        ObsvCfgDto cfgStruct = cfgIndex.getPropIndex().get(prodCodeStruct);
                        structRd = BeanUtil.copyProperties(cfgStruct, BObsvRecordResultVO.class);
                        structRd.setId(null);
                        structRd.setDetail(null);//去除配置中的明细
                        structRd.setObsvCode(cfgStruct.getObsvCode());
                        structRd.setPatientIdent(rdSrc.getPatientIdent());
                        structRd.setRecTime(rdSrc.getRecTime());
                        stuctCach.put(prodCodeStruct + ":" + recTime, structRd);
                        structRd.setPropValue(null);
                        rst.add(structRd);
                    }
                    List<BObsvRecordResultVO> tmpDetailRd = structRd.getDetail();
                    if (tmpDetailRd == null) {
                        tmpDetailRd = new ArrayList<>();
                        structRd.setDetail(tmpDetailRd);
                    }
                    tmpDetailRd.add(rstItem);
                }
            }
        }

        return rst;
    }


    /**
     * 获得生命特征参数的配置索引。 key: 生命特征参数，value：配置
     */
    public ObsvCfgIndexDto getProp2Cfg() {
        ObsvCfgIndexDto rst = new ObsvCfgIndexDto();
        ObsvCfgQueryParam param = new ObsvCfgQueryParam();
        param.setIsEnable(CommonConstant.YES_NUMBER);
        param.setIsVisible(CommonConstant.YES_NUMBER);
        param.setIsDeleted(CommonConstant.NO_NUMBER);
        List<ObsvCfgForRdDto> cfgList = bObsvCfgService.queryForRd(param);
        if (cfgList == null || cfgList.isEmpty()) {
            return rst;
        }

        for (ObsvCfgForRdDto obsvType : cfgList) {
            if (obsvType == null || obsvType.getDetail() == null || obsvType.getDetail().isEmpty()) {
                continue;
            }

            for (ObsvCfgDto item : obsvType.getDetail()) {
                if (item == null || StrUtil.isBlank(item.getObsvCode())) {
                    continue;
                }
                rst.getStructMap().put(item.getObsvCode(), item);
                rst.getPropIndex().put(item.getObsvCode(), item);
                if (item.getDetail() != null && !item.getDetail().isEmpty()) {
                    boolean isStruct = false;
                    if (ObsvConstant.TYPE_STRUCT.equals(item.getDataType())) {
                        isStruct = true;
                    }
                    for (ObsvCfgDetailDto cfgDetail : item.getDetail()) {
                        Set<String> structSet = rst.getStructIndex().get(cfgDetail.getObsvCode());
                        if (structSet == null) {
                            structSet = new LinkedHashSet<>();
                            rst.getStructIndex().put(cfgDetail.getObsvCode(), structSet);
                        }
                        structSet.add(item.getObsvCode());
                        if (isStruct) {
                            List<ObsvCfgDto> onlyStructList = rst.getOnlyStructMap().get(cfgDetail.getObsvCode());
                            if (onlyStructList == null) {
                                onlyStructList = new ArrayList<>();
                                rst.getOnlyStructMap().put(cfgDetail.getObsvCode(), onlyStructList);
                            }
                            onlyStructList.add(item);
                        }
                    }
                }
            }
        }
        return rst;
    }


    /**
     * 为医生查询观察原始记录
     *
     * @param param 查询参数
     * @return
     */
    private List<BObsvRecord> queryByDoctorInitRd(ObsvRecordQueryByDoctorParam param) {
        LambdaQueryWrapper<BObsvRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BObsvRecord::getIsDeleted, CommonConstant.NO_NUMBER);
        param.setStartTime(DateUtil.beginOfDay(new Date(param.getCurrTime())).getTime());
        param.setEndTime(DateUtil.endOfDay(new Date(param.getCurrTime())).getTime());
        queryWrapper.eq(StrUtil.isNotBlank(param.getPatientIdent()), BObsvRecord::getPatientIdent, param.getPatientIdent());
        queryWrapper.ge(param.getStartTime() != null, BObsvRecord::getRecTime, param.getStartTime());
        queryWrapper.le(param.getEndTime() != null, BObsvRecord::getRecTime, param.getEndTime());
        List<BObsvRecord> list = bObsvRecordMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * 为医生查询观察记录
     *
     * @param param 查询参数
     * @return
     */
    @Override
    public List<ObsvRecordDto> queryByDoctor(@Valid ObsvRecordQueryByDoctorParam param) {
        //为医生查询观察原始记录
        List<BObsvRecord> list = queryByDoctorInitRd(param);
        List<ObsvRecordDto> rst = new ArrayList<>();
        if (list.isEmpty()) {
            return rst;
        }
        //---------------数据处理
        LinkedHashSet<Long> shiftTimePointSet = bWorkPlanService.getAllTimePoit(param.getCurrTime(), MODEL_NAME_TIME_AXIOS);
        if (CollectionUtil.isEmpty(shiftTimePointSet)) {
            return rst;
        }
        //获得生命特征参数的配置索引。
        ObsvCfgIndexDto cfgIndex = getProp2Cfg();

        //记录缓存，key:参数名+记录时间
        Map<String, BObsvRecord> rdCach = new LinkedHashMap<>();
        //结构体记录缓存，key:参数名+记录时间
        Map<String, ObsvRecordDto> stuctCach = new LinkedHashMap<>();

        for (BObsvRecord rdSrc : list) {
            if (!shiftTimePointSet.contains(rdSrc.getRecTime())) {
                continue;
            }
            String propCode = rdSrc.getObsvCode();
            String recTime = Convert.toStr(rdSrc.getRecTime());
            String cacheKey = propCode + ":" + recTime;
            rdCach.put(cacheKey, rdSrc);
        }

        for (BObsvRecord rdSrc : list) {
            if (!shiftTimePointSet.contains(rdSrc.getRecTime())) {
                continue;
            }
            String propCode = rdSrc.getObsvCode();
            String recTime = Convert.toStr(rdSrc.getRecTime());
            String cacheKey = propCode + ":" + recTime;
            rdCach.put(cacheKey, rdSrc);
            ObsvCfgDto cfg = cfgIndex.getPropIndex().get(propCode);

            ObsvRecordDto rstItem = BeanUtil.copyProperties(rdSrc, ObsvRecordDto.class);
            if (cfg != null) {
                rstItem.setObsvName(cfg.getObsvName());
                rstItem.setDataType(cfg.getDataType());
                rstItem.setObsvType(cfg.getObsvType());
            }

            if (cfg != null && Convert.toInt(cfg.getIsVisible()) == CommonConstant.YES_NUMBER) {
                rst.add(rstItem);
            }

            Set<String> cfgStructSet = cfgIndex.getStructIndex().get(propCode);
            if (CollectionUtil.isNotEmpty(cfgStructSet)) {
                //结构体处理
                for (String prodCodeStruct : cfgStructSet) {
                    ObsvRecordDto structRd = stuctCach.get(prodCodeStruct + ":" + recTime);
                    if (structRd == null) {
                        ObsvCfgDto cfgStruct = cfgIndex.getPropIndex().get(prodCodeStruct);
                        structRd = BeanUtil.copyProperties(cfgStruct, ObsvRecordDto.class);
                        structRd.setId(null);
                        //去除配置中的明细
                        structRd.setDetail(null);
                        structRd.setObsvCode(cfgStruct.getObsvCode());
                        structRd.setPatientIdent(rdSrc.getPatientIdent());
                        structRd.setRecTime(rdSrc.getRecTime());
                        stuctCach.put(prodCodeStruct + ":" + recTime, structRd);
                        structRd.setPropValue(null);
                        rst.add(structRd);
                    }
                    List<ObsvRecordDto> tmpDetailRd = structRd.getDetail();
                    if (tmpDetailRd == null) {
                        tmpDetailRd = new ArrayList<>();
                        structRd.setDetail(tmpDetailRd);
                    }
                    tmpDetailRd.add(rstItem);
                }
            }
        }

        return rst;
    }


    /**
     * 新增或更新
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addAndUpdate(BObsvRecordSaveVO param) {
        if (param == null) {
            return null;
        }
        List<BObsvRecord> adds = new ArrayList<>();
        Set<String> codes = new HashSet<>();
        addData(param, adds, codes);
        bObsvRecordMapper.deleteByCodesAndTime(param.getPatientIdent(), param.getHospitalNumber(), param.getRecTime(), codes);
        boolean result = false;
        if (CollectionUtil.isNotEmpty(adds)) {
            result = saveBatch(adds);
        }
        return result;
    }


    private void addData(BObsvRecordSaveVO param, List<BObsvRecord> adds, Set<String> codes) {
        if (param.getDataType().equals("struct")) {
            if (CollectionUtil.isNotEmpty(param.getDetail())) {
                for (BObsvRecordSaveVO dto : param.getDetail()) {
                    addData(dto, adds, codes);
                }
            }
        } else {
            BObsvRecord yxObsvRecord = ConvertUtil.convert(param, BObsvRecord.class);
            yxObsvRecord.setCreateSource(ObsvConstant.CREATE_SOURCE_HAND);
            yxObsvRecord.setId(null);
            yxObsvRecord.setIsVisible(1);
            yxObsvRecord.setCaijiren(ContextUtil.getUserId() + "");

            //采集人工号
            yxObsvRecord.setCaijirenGh("");
            codes.add(yxObsvRecord.getObsvCode());
            adds.add(yxObsvRecord);
        }
    }


    /**
     * 获得天数
     */
    @Override
    public ObsrvUseDaysDto getDays(ObsrvUseDaysParam param) {
        ObsrvUseDaysDto rst = new ObsrvUseDaysDto();
        Set<String> obsrvCodes = param.getObserCodes();
        String patientIdent = param.getPatientIdent();
        Long startTime = param.getStartTime();
        Long endTime = param.getEndTime();
        Integer isDev = param.getIsDev();
        if (StrUtil.isBlank(patientIdent)) {
            rst.setErrorMsg("病人识别号为空");
            return rst;
        }
        if (startTime == null || endTime == null) {
            rst.setErrorMsg("开始时间或结束时间为空");
            return rst;
        }

        endTime = (DateUtil.endOfDay(new Date(endTime))).getTime();

        Set<String> typeFilte = Stream.of(param.getObserType()).collect(Collectors.toSet());
        Map<String, Set<String>> cfgMap = bObsvPtCfgService.getObsvCodeSetFinalOfLeafByType(new ObsvPtCfgForRdParam(patientIdent), typeFilte);
        if (CollectionUtil.isEmpty(cfgMap)) {
            rst.setErrorMsg("没有获取到病人的呼吸的观察项配置");
            return rst;
        }
        List<String> cfgList = cfgMap.values().stream().findFirst().get().stream().filter(o -> CollectionUtil.isEmpty(obsrvCodes) || obsrvCodes.contains(o)).collect(Collectors.toList());

        rst.setUsrDays(bObsvRecordMapper.getUseDays(patientIdent, startTime, endTime, cfgList, param.getIsDev()));

        return rst;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRecordStatus(UpdateStatusDTO updateStatusDTO) {
        bObsvRecordMapper.updateStatus(updateStatusDTO);
    }

    /**
     * 删除观察项记录
     * 特别说明：由于时间轴上的自定义时间点 必须是物理删除，为了防止冲突，这里物理删除
     *
     * @param param 删除参数
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean del(@Valid ObsvRecordCodesVO param) {
        boolean rst = false;
        for (String code : param.getObsvCodeList()) {
            if (StrUtil.isBlank(code)) {
                continue;
            }
            LambdaQueryWrapper<BObsvRecord> queryWrapper = new LambdaQueryWrapper();
            queryWrapper.eq(BObsvRecord::getHospitalNumber, param.getHospitalNumber())
                    .eq(BObsvRecord::getRecTime, param.getRecTime())
                    .eq(BObsvRecord::getObsvCode, code);
//            List<BObsvRecord> listolds = list(queryWrapper);

            //验证是否本人修改
//            if(CollectionUtil.isNotEmpty(listolds)){
//                for(BObsvRecord rd : listolds){
//                    if(null != SecurityUtil.checkRecordAuth(rd.getCreateBy() ,rd.getUpdateBy())  && rd.getCreateSource().equals(ObsvConstant.CREATE_SOURCE_HAND)){
//                        throw new BadRequestException(SecurityUtil.checkRecordAuth(rd.getCreateBy() ,rd.getUpdateBy()));
//                    }
//                }
//            }
            int rr = bObsvRecordMapper.delete(queryWrapper);
            if (rr > 0) {
                rst = true;
            }

        }
        return rst;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteData(String patientIdent, String hospitalNumber, LocalDateTime timePoint) {
        bObsvRecordMapper.deleteData(patientIdent, hospitalNumber, timePoint);
    }


    @Override
    public List<Map> getCktime(String hospitalNumber, String startTimeStr, String endTimeStr) {
        Date start = YDateUtils.strToDate(startTimeStr, YDateUtils.DATE_TIME_PATTERN);
        Date end = YDateUtils.strToDate(endTimeStr, YDateUtils.DATE_TIME_PATTERN);
        List<Map> list = new ArrayList<>();
        return list;
        //查询ck库 暂时不做 没有ck测试数据
        // return vyxIcuVsDataService.getlatesCkTime( "'"+hospitalNumber+"'",  String.valueOf(start.getTime()),  String.valueOf(end.getTime()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ObsvRecordDto> careAddAndUpdate(List<CareObsvRecordDto> params, Long recordTime, String operator, String account, String patientIdent, Set<String> obsvcodes) {
        Set<Long> times = new HashSet<>();
        times.add(YDateUtils.strToDate(YDateUtils.format(new Date(recordTime), YDateUtils.DATE_TIME_MINUTE_PATTERN)
                + ":00", YDateUtils.DATE_TIME_PATTERN).getTime());
        bObsvRecordMapper.deleteByPatAndCodeAndTime(patientIdent, obsvcodes, times, account);
        if (CollectionUtil.isEmpty(params)) {
            return new ArrayList<>();
        }
        List<BObsvRecord> yxObsvRecords = ConvertUtil.convertList(params, BObsvRecord.class);
        List<BObsvCfg> cfgs = bObsvCfgService.getObsvCfgByParam(obsvcodes);
        Map<String, List<BObsvCfg>> cfgmap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(cfgs)) {
            cfgmap = cfgs.stream().collect(Collectors.groupingBy(BObsvCfg::getObsvCode));
        }
        Map<String, List<BObsvCfg>> finalCfgmap = cfgmap;
        yxObsvRecords.forEach(v -> {
            List<BObsvCfg> cfg = finalCfgmap.get(v.getObsvCode());
            v.setCreateSource("hand");
            v.setCaijiren(operator);
            v.setCaijirenGh(account);
            if (CollectionUtil.isNotEmpty(cfg)) {
                v.setObsvId(cfg.get(0).getId());
            }
            v.setRecTime(YDateUtils.strToDate(YDateUtils.format(new Date(recordTime), YDateUtils.DATE_TIME_MINUTE_PATTERN)
                    + ":00", YDateUtils.DATE_TIME_PATTERN).getTime());
        });
        List<BObsvRecord> resultSave = new ArrayList<>();
        List<BObsvRecord> result = new ArrayList<>();
        for (BObsvRecord record : yxObsvRecords) {
            resultSave.add(record);
            result.add(record);
        }
        if (CollectionUtil.isNotEmpty(resultSave)) {
            saveBatch(resultSave);
        }
        return ConvertUtil.convertList(result, ObsvRecordDto.class);
    }

    @Override
    public List<BObsvRecord> getPulseHeartRateListData(String hospitalNumber, String startTime, String endTime) {
        return bObsvRecordMapper.getPulseHeartRateListData(hospitalNumber, startTime, endTime);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean IotDataCollectionOfSave(List<IotDataResult> iotDataList) {
        DefUserInfoResultVO defUserInfoResultVO = oauthUserBiz.getUserById(ContextUtil.getUserId());
        List<BObsvRecord> obsvRecordList=new ArrayList<>();
        for (int i = 0; i <iotDataList.size() ; i++) {
            IotDataResult iotDataResult=iotDataList.get(i);

            // 创建 ObjectMapper 实例
            ObjectMapper objectMapper = new ObjectMapper();

            String jsonString=iotDataResult.getObsvData();
            Map<String, Object> obsvData =new HashMap<>();
            try {
                // 将 JSON 字符串转换为 Map<String, Object>
                 obsvData = objectMapper.readValue(jsonString, Map.class);

                // 输出 Map
                System.out.println(obsvData);
            } catch (Exception e) {
                e.printStackTrace();
            }
//            Map<String, Object> obsvData=iotDataResult.getObsvData();
            if (obsvData != null && !obsvData.isEmpty()) {
                // 使用 forEach 遍历 map
                obsvData.forEach((key, value) -> {
                    if (value != null && !value.toString().trim().isEmpty()) {
                        System.out.println("键: " + key + ", 值: " + value);
                        BObsvRecord bObsvRecord = new BObsvRecord();
                        bObsvRecord.setObsvCode(key);


                        LocalDateTime createdTime = iotDataResult.getCreatedTime();
                        LocalDateTime modifiedTime = createdTime.withSecond(0).withNano(0);  // 设置秒为 00，纳秒部分也清零
                        //为了对应观察项的列轴时间 秒部分设置为00
                        bObsvRecord.setRecTime(PDateUtils.getTimestampOfDateTime(modifiedTime));
                        bObsvRecord.setRealTime(iotDataResult.getCreatedTime());
                        //bObsvRecord.setRecTime(PDateUtils.getTimestampOfDateTime(iotDataResult.getCreatedTime()));
                        if(null!=bObsvCfgService.getOneByCodeAndNoDel(key)){
                            bObsvRecord.setObsvId(bObsvCfgService.getOneByCodeAndNoDel(key).getId());
                        }

                        bObsvRecord.setCaijiren(defUserInfoResultVO.getNickName());
                        bObsvRecord.setCaijirenGh(defUserInfoResultVO.getUsername());
                        bObsvRecord.setPatientIdent(iotDataResult.getPatientIdent());
                        bObsvRecord.setPropValue((String) value);
                        bObsvRecord.setIsDeleted(0);
                        bObsvRecord.setHospitalNumber(iotDataResult.getHospitalNumber());
                        bObsvRecord.setCreateSource("dev");
                        bObsvRecord.setIsVisible(1);

                        obsvRecordList.add(bObsvRecord);
                    }
                });
            }


        }
        Boolean result=this.saveBatch(obsvRecordList);
        return result;
    }

}


